import { getToken } from "@/api/oss";
import store from "@/store";
import OSS from "ali-oss";
import dayjs from "dayjs";
import { IClient } from ".";
import storageManger from "../storageManger";

export default class AliyunOSS implements IClient {
	private ossClient?: OSS;
	private _stsUrl: string;
	private _region: string;
	private _bucket: string;

	/**
	 *
	 * @param stsUrl sts请求地址
	 * @param region 阿里云region
	 * @param bucket 阿里云bucket
	 */
	constructor(stsUrl: string, region: string, bucket: string) {
		this._stsUrl = stsUrl;
		this._region = region;
		this._bucket = bucket;
	}

	async getClient() {
		return new Promise<OSS>(async (reslove, reject) => {
			if (this.ossClient) {
				reslove(this.ossClient);
				return;
			}
			try {
				if (
					store.state.stsToken?.expiration &&
					dayjs().isBefore(store.state.stsToken.expiration)
				) {
					this.ossClient = new OSS({
						accessKeyId: store.state.stsToken.accessKeyId,
						accessKeySecret: store.state.stsToken.accessKeySecret,
						stsToken: store.state.stsToken.securityToken,
						region: this._region,
						bucket: this._bucket,
					});

					reslove(this.ossClient);
					return;
				}
				let ossToken = await getToken(this._stsUrl);
				storageManger.set("stsToken", ossToken.credentials);
				this.ossClient = new OSS({
					accessKeyId: ossToken.credentials.accessKeyId,
					accessKeySecret: ossToken.credentials.accessKeySecret,
					stsToken: ossToken.credentials.securityToken,
					region: this._region,
					bucket: this._bucket,
					// 刷新临时访问凭证。
					refreshSTSToken: async () => {
						const refreshToken = await getToken(this._stsUrl);
						return {
							accessKeyId: refreshToken.credentials.accessKeyId,
							accessKeySecret: refreshToken.credentials.accessKeySecret,
							stsToken: refreshToken.credentials.securityToken,
						};
					},
				});
				reslove(this.ossClient);
			} catch (error) {
				throw new Error("阿里云OSS请求失败！");
			}
		});
	}
	upload(file: File, fileFullPath: string) {
		return new Promise<{ fileId: string }>(async (reslove, reject) => {
			try {
				await this.getClient();

				let response = await this.ossClient!.put(fileFullPath, file);
				if (response.res.status != 200) {
					reject(response.res);
				} else {
					reslove({ fileId: fileFullPath });
				}
			} catch (error) {
				reject(error);
			}
		});
	}

	downloadStream(fileFullName: string) {
		return new Promise<Blob>(async (reslove, reject) => {
			let url = await this.download(fileFullName);
			fetch(url).then(async (res) => {
				reslove(await res.blob());
			});
		});
	}
	/**
	 * 获取文件地址
	 * @param fileFullName 文件全路径
	 * @param isOriginal  是否原图
	 * @param params  缩略图参数
	 * @returns 图片地址
	 */
	download(fileFullName: string, isOriginal?: boolean, params?: any) {
		return new Promise<string>(async (reslove, reject) => {
			try {
				await this.getClient();

				// 判断文件是否存在，不存在走catch
				await this.ossClient!.head(fileFullName);
				if (isOriginal) {
					// 原图
					let url = this.ossClient!.signatureUrl(fileFullName);
					reslove(url);
				} else {
					// 缩略图
					let url = this.ossClient!.signatureUrl(
						fileFullName,
						params || {
							process: "image/resize,w_150",
						}
					);
					reslove(url);
				}
			} catch (error) {
				reject(error);
			}
		});
	}
	downloadZip(fileFullName: string, fileName: string) {
		return new Promise<string>(async (reslove, reject) => {
			try {
				await this.getClient();
				let url = this.ossClient!.signatureUrl(fileFullName);
				const iframe = document.createElement("iframe");
				iframe.setAttribute("src", url);
				iframe.setAttribute("hidden", "hidden");
				document.body.appendChild(iframe);
				reslove("");
			} catch (error) {
				reject(error);
			}
		});
	}
	isExist(fileId: string) {
		return new Promise<boolean>(async (reslove, reject) => {
			try {
				await this.getClient();
				let info = await this.ossClient!.head(fileId);
				if (info.res.status == 200) {
					reject(false);
				} else if (info.res.status == 404) {
					reslove(true);
				} else {
					reject(`错误${info.res.status}`);
				}
			} catch (error) {
				reject(error);
			}
		});
	}
}
